using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using CHEnhanceEfCore.DataBase;
using CHEnhanceEfCore.Models;
using CHEnhanceEfCore.System;
using Elastic.Clients.Elasticsearch;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;

namespace CHEnhanceEfCore.Service.impl
{
    /// <summary>
    /// author: chenhao
    /// </summary>
    public class UserServiceImpl : IUserService
    {
        private readonly ChEnhanceDbContext _dbContext;
        private readonly AppSettings _appSettings;
        private readonly IRoleService _roleService;
        private readonly ElasticsearchClient _elasticsearchClient;

        public UserServiceImpl(ChEnhanceDbContext dbContext, AppSettings appSettings, IRoleService roleService, ElasticsearchClient elasticsearchClient)
        {
            _dbContext = dbContext;
            _appSettings = appSettings;
            _roleService = roleService;
            _elasticsearchClient = elasticsearchClient;
        }

        public async Task saveAsync(User user)
        {
            if (Guid.Empty.Equals(user.userId))
            {
                user.userId = new Guid();
            }

            string userName = user.username;
            string userEmail = user.email;
            string userPhoneNumber = user.phoneNumber;

            User oldUser = await _dbContext.userSet.Where(u => (Guid.Empty.Equals(user.userId) && u.userId.Equals(user.userId))
                                                               || u.username.Equals(userName)
                                                               || u.email.Equals(userEmail)
                                                               || u.phoneNumber.Equals(userPhoneNumber))
                .FirstOrDefaultAsync();
            if (oldUser != null)
            {
                throw new Exception("用户已存在");
            }
            
            await _dbContext.AddAsync(user);
            await _dbContext.SaveChangesAsync();

            IndexResponse indexResponse = await _elasticsearchClient.IndexAsync(user, idx => { idx.Index("user").Id(user.userId); });
            
            if (!indexResponse.IsValidResponse)
            {
                throw new Exception("保存用户信息到ElasticSearch失败");
            }
        }

        public async Task<List<User>> getUserListAsync()
        {
            var searchAsync = await _elasticsearchClient.SearchAsync<User>(s =>
                s.Index("user")
                    .From(0)
                    .Size(10)
                    .Query(q => q.MatchAll()));
            // .Query(q => { q.Match(qm => qm.Field(u => u.username.Equals("test2"))); }));
            List<User> users = null;
            if (searchAsync.IsValidResponse)
            {
                users = searchAsync.Documents.ToList();
                Console.WriteLine("使用ES的用户列表");
                return users;
            }

            users = await _dbContext.userSet.ToListAsync();
            if (users != null)
            {
                await _elasticsearchClient.BulkAsync(b => b.Index("user").IndexMany(users));
            }

            return await _dbContext.userSet.ToListAsync();
        }

        public async Task<dynamic> loginAsync(User user)
        {
            string userName = user.username;
            string password = user.password;
            User oldUser = await _dbContext.userSet.FirstOrDefaultAsync(u => u.username.Equals(userName) && u.password.Equals(password));
            if (null != oldUser)
            {
                Guid userId = oldUser.userId;
                //获取权限code
                List<string> roleCodeList = await _roleService.getRoleCodesByUserIdAsync(userId);
                //todo 获取权限标识
                List<string> permissionList = new List<string>()
                {
                    "sys:user:list",
                    "sys:user:add",
                };
                //创建用户身份标识，可按需要添加更多信息
                var claims = new List<Claim>
                {
                    new("userId", userId.ToString()),
                    new("username", userName),
                    new(ClaimTypes.Role, string.Join(",", roleCodeList)),
                    new("permission", string.Join(",", permissionList)),
                    // new Claim("normalPermissions", string.Join(";",customClaims.normalPermissions)),
                    new(JwtRegisteredClaimNames.Sub, userName),
                };
                var expireTime = DateTime.Now.AddSeconds(_appSettings.expireSeconds);
                //创建令牌
                var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_appSettings.tokenSecret));
                var jwt = new JwtSecurityToken(
                    claims: claims,
                    expires: expireTime,
                    signingCredentials: new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256));
                string accessToken = new JwtSecurityTokenHandler().WriteToken(jwt);
                return new
                {
                    accessToken,
                    expireTime = expireTime.ToString("dd-MM-yyyy HH:mm:mm"),
                    tokenType = JwtBearerDefaults.AuthenticationScheme,
                };
            }

            return null;
        }

        public async Task<User> getUserInfoAsync(Guid userId)
        {
            return await _dbContext.userSet.Where(u => u.userId.Equals(userId)).FirstOrDefaultAsync();
        }
    }
}